;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; lcd.inc is een include file voor het gebruik van het lcd scherm op het
; ADuC800 bord. Het bord wordt gebruikt met een 1*16 of een 2*16 karakter
; display. De basisroutines zijn bruikbaar voor alle types schermen (de
; gebruiker moet dan wel zelf wakker liggen over cursorrouting).
; De hogere routines gaan er van uit dat we een 2*16 karakter display gebruiken.
; Parameters worden doorgegeven via de accu, b register, dptr of r0.
; De routines gebruiken geen registers. Alle timing wordt automatisch aangepast
; aan de waarden in het pllcon register. De routines zijn geoptimaliseerd naar
; de aansluitingen op het ADuC800 bord.
;
; De 2 overblijvende klemmen van poort 0 (p0.0 en p0.1) worden niet aangepast.
;
; GESCHREVEN OP 02/1994 DOOR MARC ROGGEMANS als lcd.drv
;      -aangepast door Roggemans Marc (MGM) op 11/2004 voor ADuC800 kaart als 
;       aduclcd0.inc
;      -aangepast door Roggemans Marc (MGM) op 11/11/2004
;       aduclcd1.inc
;             -00dh en 00ah worden door outchar verwerkt
;             -bij de init wordt het display anders opgestart
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

e             bit    p0.2                 ;enable
rs            bit    p0.3                 ;register select

lcdport       EQU    p0                   ;SELECTIE POORT 0

cleardisp     EQU    001H                 ;LEEG MAKEN VAN HET SCHERM
cursathom     EQU    002H                 ;CURSOR OP DE EERSTE PLAATS ZETTEN

entrymode     EQU    00000110B            ;CURSOR NAAR RECHTS, SCHERM VAST
displayon     EQU    00000001B            ;HOMEN EN CLEAR CURSOR
displayof     EQU    00001000B            ;DISPLAY OFF, CURSOR OFF
cursoroff     EQU    00001100B            ;DISPLAY ON ZONDER CURSOR
cursoronb     EQU    00001111B            ;CURSOR ON AND BLINK
cursoronn     EQU    00001110B            ;CURSOR ON NO BLINK
functions     EQU    00101000B            ;INTERFACE LENGTE EN KARAKTER FONT
cgram         EQU    01000000B            ;SELECTIE KARAKTER GENERATOR RAM
ddram         EQU    10000000B            ;SELECTIE DATA DISPLAY RAM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; initlcd     zal het scherm resetten en initialiseren voor gebruik via een 4
; bit bus. De routine zet het scherm klaar voor normaal gebruik: ingave van
; links naar rechts zonder display shift, normale karakterfont. De kursor staat
; aan als een knipperend lijntje onderaan de regel. Het scherm is leeg.
;
; registergebruik: geen
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

initlcd:      push   acc           ;registers op stack plaatsen
              push   psw
              mov    lcdport,#003h ;poort in uitgangstoestand zetten
                                   ;let op:twee laagste bits worden
                                   ;niet gebruikt
              mov    a,#010h       ;bij opstarten meer dan 30ms wachten
initlcd1:     lcall  delay2ms
              djnz   acc,initlcd1
              mov    a,#00110000b  ;volgende drie schrijfbeurten zijn 
              lcall  outhnibc      ;een truuk om het display altijd opgestart
              lcall  delay2ms      ;te krijgen.
              mov    a,#00110000b
              lcall  outhnibc
              lcall  delay2ms
              mov    a,#00110000b
              lcall  outhnibc
              lcall  delay2ms
              mov    a,#00100000b  ;instellen 4 bit interface gebruiken
              lcall  outhnibc      ;hoge nibble naar het controleregister
              lcall  delay2ms      ;niet nodig volgens datasheet
              mov    a,#functions  ;4 bit interface, twee lijnen 5*8 dots
              lcall  outc          ;naar display
              lcall  delay2ms      ;is iets te lang volgens datasheet
              mov    a,#cursoronb  ;display on cursor on and blink
              lcall  outc
              lcall  delay2ms      ;ook deze delay is iets te lang
              mov    a,#displayon  ;clear display and home cursor
              lcall  outc
              lcall  delay2ms      ;deze wachttijd is bijna juist
              mov    a,#entrymode  ;display klaar zetten normaal gebruik
              lcall  outc
              lcall  delay2ms      ;wachten weer veel te lang
              pop    psw           ;registers terug in orde zetten
              pop    acc
              ret                  ;einde van de initialisatie

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outcharlcd  zal de ascii code in de accu naar het lcd scherm sturen. De codes
; lager dan 020h worden als controlekarakters bekeken met volgende acties:
;      00dh   =cursor in de home positie
;      00ch   =form feed    =scherm leeg maken en kursor op lacatie 000h
;      00ah   =cursor op tweede lijn plaatsen
;      001h   =cursor on blink
;      002h   =cursor on blink
;      003h   =cursor off
;      080h-0ffh     =cursor plaatsen op dit adres -80h
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; we gaan eerst na of het een ascii code betreft van een symbool. Als dat zo is,
; dan mag de data direct naar het dataregister van het scherm.
; Betreft een controle karakter, dan is een andere aanpak nodig (zie verder).

outcharlcd:   push   acc           ;registers op stack
              push   psw
              cjne   a,#080h,outcharlcd1  ;hogere codes zijn adressen
outcharlcd1:  jnc    outcharlcd9   ;als geen carry dan is de code een address
              cjne   a,#020h,outcharlcd2  ;hogere codes zijn ascii van symbolen
outcharlcd2:  jnc    outcharlcd8   ;als geen carry dan ascii code naar display

; de code in de accu is geen adres of geen geldige ascii code van een symbool.
; Het is dus een opdracht die we moeten uitvoeren.

              cjne   a,#00ch,outcharlcd3  ;geen form feed, dan jump
              mov    a,#cleardisp         ;scherm leegmaken
              lcall  outc                 ;naar controleregister
              sjmp   outcharlcde          ;afsluiten
              
outcharlcd3:  cjne   a,#001h,outcharlcd4  ;geen cursor on blink
              mov    a,#cursoronb         ;cursoron met blink
              lcall  outc
              sjmp   outcharlcde 

outcharlcd4:  cjne   a,#002h,outcharlcd5  ;geen cursor on no blink
              mov    a,#cursoronn         ;cursoron no blink
              lcall  outc
              sjmp   outcharlcde

outcharlcd5:  cjne   a,#003h,outcharlcd6  ;geen cursor off, dus afsluiten routine
              mov    a,#cursoroff         ;cursor uitschakelen
              lcall  outc
              sjmp   outcharlcde

outcharlcd6:  cjne   a,#00dh,outcharlcd7  ;geen cursor home zonder clear scherm
              mov    a,#cursathom         ;cursor in home positie
              lcall  outc
              sjmp   outcharlcde

outcharlcd7:  cjne   a,#00ah,outcharlcde  ;line feed gevraagd (zet cursor op
                                          ;tweede lijn
              mov    a,#0c0h
              lcall  outc
              sjmp   outcharlcde

; dit label wordt uitgevoerd als de code in de accumulator een geldige ascii code
; is. dit mag naar het data register.

outcharlcd8:  lcall  outd          ;klaar
              sjmp   outcharlcde   ;einde routine

; dit label wordt uitgevoerd als de code in de accu een adres is. Dit adres is
; eigenlijk 80 te groot. Dat komt echter goed uit als commando om een adrers te
; te schrijven.

outcharlcd9:  lcall  outc          ;klaar
outcharlcde:  pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outniblcd     zal de lage nibble omzetten in een ascii code en die afdrukken
; op het lcd scherm.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outniblcd:    push   acc           ;registers op stack zetten
              push   psw
              anl    a,#00fh       ;laagste 4 bits overhouden
              add    a,#030h       ;omvormen naar ascii codes 0-9
              cjne   a,#03ah,outniblcd1   ;als groter dan dit nog 7 bijtellen
outniblcd1:   jc     outniblcde    ;als carry dan omzetting klaar
              add    a,#007h       ;omvormen naar hoofdletter
outniblcde:   lcall  outd          ;naar het scherm
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outbytelcd    zal de inhoud van de accu afdrukken op het lcd scherm.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outbytelcd:   push   acc           ;registers op de stack zetten
              push   psw
              swap   a             ;bitjes omruilen
              lcall  outniblcd
              swap   a             ;nog eens
              lcall  outniblcd
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; dispdptrlcd   zal de inhoud van de dptr afdrukken op het lcd scherm
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dispdptrlcd:  push   acc           ;registers bewaren op stack
              push   psw
              mov    a,dph         ;hoge deel eerst naar het scherm
              lcall  outbytelcd
              mov    a,dpl         ;dan het lage deel
              lcall  outbytelcd
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outmsgalcd  zal een string ascii codes op het scherm plaatsen. Het startadres
; van de string staat in de dptr. De string wordt afgesloten met een 000h.
; De routine gebruikt outcharlcd voor het sturen van karakters naar het LCD
; scherm. Positionnering van de cursor en cursorcontrole kan in de ascii string
; opgenomen worden met de pseudo ascii codes (zie outcharlcd).
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outmsgalcd:   push   acc           ;registers op de stack
              push   psw
              push   dph           ;ook de data pointer
              push   dpl

;We lezen karakters uit code memory tot de 000h code gevonden wordt.

outmsgalcd1:  clr    a             ;waarde zit in onze weg
              movc   a,@a+dptr     ;waarde lezen
              jz     outmsgalcde   ;als 0 dan naar einde springen

; de code is niet 0 dus versturen met outchar

              lcall  outcharlcd    ;weg er mee
              inc    dptr          ;naar volgende ascii code wijzen
              ljmp   outmsgalcd1   ;lus sluiten

outmsgalcde:  pop    dpl           ;registers herstellen
              pop    dph
              pop    psw
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; regtolcd    is een subroutine die de gegevens uit een register-buffer naar
; de lcd stuurt. De routtine gaat er van uit dat er op het scherm maar 16
; karakters per lijn zitten. De string ascii codes in het geheugen moet 32
; karakters bevatten. De routine verwacht in r0 het startadres van de buffer.
;
; de routine gebruikt geen registers
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


regtolcd:     push   acc           ;registers op de stack
              push   psw
              mov    a,r0
              push   acc
              mov    a,r1
              push   acc
              mov    r1,#000h      ;werkt als loopcounter
regtolcd1:    mov    a,@r0         ;karakter lezen
              lcall  outcharlcd    ;weg er mee
              inc    r0
              inc    r1
              cjne   r1,#016d,regtolcd1   ;als deze waarde 16 is moet een
                                          ;nieuwe lijn genomen worden
              mov    a,#(80h+40h)  ;dit is het eerste adres op de tweede lijn
              lcall  outcharlcd    ;hiermee plaatsen we de cursor op de juiste
                                   ;plaats
              
regtolcd2:    mov    a,@r0         ;karakter lezen
              lcall  outcharlcd    ;weg er mee
              inc    r0
              inc    r1
              cjne   r1,#032d,regtolcd2   ;als deze waarde 32 is stoppen
              pop    acc
              mov    r1,a
              pop    acc
              mov    r0,a
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outd is een routine die naar het data register van het display een
; volledige byte stuurt.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outd:         push   acc           ;registers op stack zetten
              push   psw
              lcall  outhnibd      ;hoogste vier bits verzenden
              lcall  delay60us     ;niet echt nodig
              swap   a             ;bitjes omruilen
              lcall  outhnibd      ;naar het scherm sturen
              lcall  delay60us     ;altijd goed
              pop    psw           ;registers terug herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outhnibd stuurt de hoge 4 bits van de accu naar het data register van het
; lcd scherm.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outhnibd:     push   acc           ;registers op stack plaatsen
              push   psw
              setb   rs            ;controle lijn in orde
              clr    e             ;deselectie display
              anl    a,#0f0h       ;4 meest beduidende bits afzonderen
              orl    a,#00bh       ;laagste 2 pinnen op 1 zetten en rs op 1
              mov    lcdport,a
              setb   e             ;display enabelen
              nop                  ;450ns is normaal gezien voldoende
              clr    e             ;display deselecteren
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outc is een routine die naar het controleregister van het display een
; volledige byte stuurt.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outc:         push   acc           ;registers op stack zetten
              push   psw
              lcall  outhnibc      ;hoogste vier bits verzenden
              lcall  delay2ms      ;niet echt nodig
              swap   a             ;bitjes omruilen
              lcall  outhnibc      ;naar het scherm sturen
              lcall  delay2ms      ;altijd goed voor traagste commando
              pop    psw           ;registers terug herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; outhnibc stuurt de hoge 4 bits van de accu naar het controle register van het
; lcd scherm.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

outhnibc:     push   acc           ;registers op stack plaatsen
              push   psw
              clr    rs            ;controle lijn in orde
              clr    e             ;deselectie display
              anl    a,#0f0h       ;4 meest beduidende bits afzonderen
              orl    a,#003h       ;laagste 2 pinnen op 1 zetten
              mov    lcdport,a
              setb   e             ;display enabelen
              nop                  ;450ns is normaal gezien voldoende
              clr    e             ;display deselecteren
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; BUILD0 IS EEN ROUTINE DIE DE KARAKTERGENERATOR RAM ZAL LADEN MET HET
; BITPATROON VOOR 8 KARAKTERS. DE ROUTINE GEBRUIKT EEN BITMAP OP HET ADRES
; IN DPTR. DE TABEL WORDT AFGESLOTEN DOOR EEN BYTE MET BIT 7=1. DE ROUTINE
; GEBRUIKT DPTR, ACC, PSW EN ENKELE LCD.DRV ROUTINES. NA HET VULLEN VAN DE
; DATA RAM WORDT OPNIEUW ADRES 0 VAN DE DISPLAY RAM GESELECTEERD. ER WORDT GEEN
; DATA GESCHREVEN.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BUILD:        MOV    A,#CGRAM      ;TOEGANG TOT KARAKTER GENERATOR RAM
BUILD1:       LCALL  OUTC          ;NAAR SCHERM VERSTUREN
BUILD3:       MOV    A,#000H       ;ACCU OP NUL ZETTEN
              MOVC   A,@A+DPTR     ;EERSTE CODE UIT TABEL LEZEN
              LCALL  OUTD          ;NAAR KARAKTER GENERATOR RAM STUREN
              JB     ACC.7,BUILD2  ;ALS BIT 1 DAN EINDE
              INC    DPTR          ;NAAR VOLGENDE LOKATIE WIJZEN
              SJMP   BUILD3
BUILD2:       MOV    A,#DDRAM      ;DATA DISPLAY RAM SELECTEREN
              LCALL  OUTC          ;NAAR KONTROLE REGISTER STUREN
              RET                  ;EINDE VAN DE ROUTINE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Delay2ms is een vertragingsroutine van 2ms.
;
; De routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delay2ms:     push   acc           ;registers op de stack zetten
              push   psw
              mov    a,#032d       ;aantal keer 60us wachten
delay2ms1:    lcall  delay60us
              djnz   acc,delay2ms1
              pop    psw           ;registers herstellen
              pop    acc
              ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; delay routine van 60us.
; De tijdsvertraging klopt bij de hoogste kloksnelheid van de
; controller. Bij de traagste snelheid wordt de routine overgeslagen.
;
; de routine gebruikt geen registers.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delay60us:    push   acc           ;registers op de stack plaatsen
              push   psw
              mov    a,pllcon      ;pllcon inlezen
              anl    a,#00000111b  ;beduidende bits overhouden

; hoe kleiner de waarde in de pllcon, hoe sneller de controller loopt.
; door wat bitbangen maken we er een bruikbare waarde van.

              cjne   a,#00000111,delay60us2  ;als traagste snelheid stoppen
              pop    acc           ;registers herstellen
              pop    psw
              ret

delay60us2:   mov    a,#25d        ;loopcounter laden
delay60us1:   djnz   acc,delay60us1  ;telkens twee cycles tijd verliezen
              pop    psw
              pop    acc
              ret
